home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / streaming / qtspacketizerreassembler / imaaudiortp / sources / rtprssmimaaudio.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  24.1 KB  |  850 lines

  1. /*
  2.     File:        RTPRssmIMAAudio.c
  3.  
  4.     Contains:    Definition of IMA Audio RTPReassembler
  5.  
  6.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  7.  
  8.     
  9.     
  10.     OVERVIEW
  11.     
  12.     QuickTime Streaming software uses an RTPReassembler to extract sample data
  13.     from incoming RTP packets.  A base RTPReassembler defined by QuickTime
  14.     Streaming does much of the work of reassembling.  A derived RTPReassembler
  15.     extends the base to interpret a specific RTP payload format, to select an
  16.     appropriate StreamHandler to process reassembled sample data, and to
  17.     handle network packet loss.
  18.     
  19.     This reassembler extends or fully implements the following interface and
  20.     delegates all other calls to its base.
  21.         
  22.         
  23.         STANDARD COMPONENT INTERFACE
  24.         ----------------------------
  25.         
  26.         CallComponentOpen()                Allocate and initialize storage for
  27.                                         instance variables.
  28.         
  29.         CallComponentClose()            Reverse the effects of
  30.                                         CallComponentOpen().
  31.         
  32.         CallComponentVersion()            Return the instance's version.
  33.         
  34.         CallComponentTarget()            Update the instance's inheritance graph.
  35.         
  36.         
  37.         
  38.         RTP REASSEMBLER INTERFACE
  39.         ------------------------------
  40.         
  41.         RTPRssmInitialize()                Prepare to reassemble sample data.
  42.         
  43.         RTPRssmComputeChunkSize()        Determine the size of buffer needed for
  44.                                         the data in a list of network packets.
  45.         
  46.         RTPRssmAdjustPacketParams()        Adjust fields of an RTPRssmPacket to
  47.                                         reflect the properties of its payload.
  48.         
  49.         RTPRssmCopyDataToChunk()        Copy sample data from a packet list to
  50.                                         a data buffer.
  51.         
  52.         RTPRssmSendPacketList()            Prepare to process or discard a list of
  53.                                         packets.
  54.         
  55.         RTPRssmHasCharacteristic()        Indicate whether the reassembler has the
  56.                                         specified characteristic.
  57.         
  58.         RTPRssmReset()                    End processing of the current stream of
  59.                                         network packets.
  60. */
  61.  
  62.  
  63.  
  64. /* ---------------------------------------------------------------------------
  65.  *        H E A D E R S
  66.  * ---------------------------------------------------------------------------
  67.  */
  68.  
  69. #include "RTPRssmIMAAudio.h"
  70. #include "RTPRssmIMAAudioResources.h"
  71. #include <FixMath.h>
  72. #include <string.h>
  73.  
  74.  
  75.  
  76. /* ---------------------------------------------------------------------------
  77.  *        R T P    R E A S S E M B L E R    P R O T O T Y P E S
  78.  * ---------------------------------------------------------------------------
  79.  *
  80.  *    QTStreamingComponents.k.h uses these macros to declare prototypes for
  81.  *    the RTPReassembler calls defined in this file.
  82.  *
  83.  */
  84.  
  85. #define RTPRSSM_BASENAME()                RTPRssmIMAAudio_
  86. #define RTPRSSM_GLOBALS()                RTPRssmIMAAudioInstanceData **
  87.  
  88. #include <QTStreamingComponents.k.h>
  89.  
  90.  
  91.  
  92. /* ---------------------------------------------------------------------------
  93.  *        C O M P O N E N T    D I S P A T C H    H E L P E R
  94.  * ---------------------------------------------------------------------------
  95.  *
  96.  *    ComponentDispatchHelper.c uses these macros to define a dispatcher and to
  97.  *    declare prototypes for the core component calls defined in this file.  For
  98.  *    Mac OS, it defines the routine descriptor that serves as the component
  99.  *    entry point.  The name of the routine descriptor is the macro expansion of
  100.  *        
  101.  *        CALLCOMPONENT_BASENAME()##ComponentDispatchRD
  102.  *    
  103.  *    The name of the dispatcher is the macro expansion of
  104.  *    
  105.  *        CALLCOMPONENT_BASENAME()##ComponentDispatch
  106.  *
  107.  */
  108.  
  109. #define CALLCOMPONENT_BASENAME()        RTPRSSM_BASENAME()
  110. #define CALLCOMPONENT_GLOBALS()            RTPRSSM_GLOBALS() storage
  111. #define COMPONENT_DISPATCH_FILE            "RTPRssmIMAAudioDispatch.h"
  112. #define COMPONENT_C_DISPATCHER            1
  113. #define COMPONENT_UPP_SELECT_ROOT()        RTPRssm
  114. #define GET_DELEGATE_COMPONENT()        ( ( **storage ).itsBase )
  115.  
  116. #include <ComponentDispatchHelper.c>
  117.  
  118.  
  119.  
  120. #pragma mark *        INTERNAL IMPLEMENTATION
  121. #pragma mark -
  122. /* ---------------------------------------------------------------------------
  123.  *        I N T E R N A L    I M P L E M E N T A T I O N
  124.  * ---------------------------------------------------------------------------
  125.  */
  126.  
  127.  
  128.  
  129. /* ---------------------------------------------------------------------------
  130.  *        __GetNewSampleDescription()
  131.  * ---------------------------------------------------------------------------
  132.  *
  133.  *    Create a new SampleDescription for this reassembler's payload using the
  134.  *    given payload attributes.
  135.  *
  136.  */
  137.  
  138. static
  139. ComponentResult
  140. __GetNewSampleDescription(
  141.     const IMAAudioPayload *        inPayloadAttributes,
  142.     SampleDescriptionHandle *    outDescription )
  143. {
  144.     ComponentResult            theResult = noErr;
  145.     SoundDescriptionHandle    theDescription;
  146.     
  147.     
  148.     theDescription =
  149.         REINTERPRET_CAST( SoundDescriptionHandle )(
  150.             NewHandleClear( sizeof( **theDescription ) ) );
  151.     
  152.     if( theDescription )
  153.     {
  154.         *outDescription = REINTERPRET_CAST( SampleDescriptionHandle )( theDescription );
  155.         
  156.         ( **theDescription ).descSize = sizeof( **theDescription );
  157.         ( **theDescription ).dataFormat = kIMAAudioDataFormat;
  158.         ( **theDescription ).resvd1 = 0;
  159.         ( **theDescription ).resvd2 = 0;
  160.         ( **theDescription ).dataRefIndex = 0;
  161.         ( **theDescription ).version = 0;
  162.         ( **theDescription ).revlevel = 0;
  163.         ( **theDescription ).vendor = kComponentManufactureType;
  164.         
  165.         ( **theDescription ).numChannels =
  166.             IMAAudioPayloadChannelCount( inPayloadAttributes );
  167.         
  168.         ( **theDescription ).sampleSize = 16;
  169.         ( **theDescription ).compressionID = 0;
  170.         ( **theDescription ).packetSize = 0;
  171.         ( **theDescription ).sampleRate =
  172.             IMAAudioPayloadSampleRate( inPayloadAttributes );;
  173.     }
  174.     
  175.     else
  176.     {
  177.         *outDescription = 0;
  178.         
  179.         theResult = MemError();
  180.         
  181.         if( theResult == noErr )
  182.             theResult = memFullErr;
  183.     }
  184.     
  185.     return( theResult );
  186. }
  187.  
  188.  
  189.  
  190. /* ---------------------------------------------------------------------------
  191.  *        __GetPayload()
  192.  * ---------------------------------------------------------------------------
  193.  *
  194.  *    Return a pointer to the start of a packet's payload.
  195.  *
  196.  */
  197.  
  198. static
  199. IMAAudioPayload *
  200. __GetPayload(
  201.     RTPRssmPacket *        inPacket )
  202. {
  203.     return( 
  204.         REINTERPRET_CAST( IMAAudioPayload * )(
  205.             &inPacket->streamBuffer->rptr[ inPacket->transportHeaderLength ] ) );
  206. }
  207.  
  208.  
  209.  
  210. /* ---------------------------------------------------------------------------
  211.  *        __FillMissingData()
  212.  * ---------------------------------------------------------------------------
  213.  *
  214.  *    Synthesize data for missing audio frames.  This implementation zeros out
  215.  *    missing frames to synthesize silence.
  216.  */
  217.  
  218. static
  219. void
  220. __FillMissingData(
  221.     RTPRssmPacket *        inPackets,
  222.     UInt16                inGroupStartSequenceNumber,
  223.     UInt32                inInterleaveCount,
  224.     SHChunkRecord *        inChunk )
  225. {
  226.     IMAAudioFrame *        theFrames;
  227.     UInt32                theFrameCount;
  228.     UInt16                theExpectedSequenceNumber;
  229.     RTPRssmPacket *        thePacket;
  230.     UInt16                theMissingPacketCount;
  231.     UInt32                theIndex;
  232.     
  233.     
  234.     /*
  235.         For now, this function is just for looks, as it doesn't actually
  236.         produce the desired audible effect.  The problem is that the
  237.         decompressor doesn't use all data in each frame, so it doesn't
  238.         necessarily decode zeroed frames as silence, and inserting zeroed
  239.         frames into the data stream usually distorts the decoding of some
  240.         subsequent frames.
  241.         
  242.         IMPORTANT    The sequence number computations in this function work
  243.                     because the packets are in order and the separation
  244.                     between the packets is guaranteed to be within the
  245.                     precision of the RTP sequence number field (i.e., less
  246.                     than 16 bits, or 65536 packets).  When computing with
  247.                     sequence numbers of packets that might be separated by
  248.                     more than 65535 packets, a reassembler must extend the
  249.                     precision of the sequence numbers, for instance by
  250.                     using the inNumWraparounds parameter of
  251.                     RTPRssmHandleNewPacket() or by using the timeStamp
  252.                     field of RTPRssmPacket structures.
  253.     */
  254.     
  255.     theFrames =
  256.         REINTERPRET_CAST( IMAAudioFrame * )( CONST_CAST( UInt8 * )( inChunk->dataPtr ) );
  257.     
  258.     theFrameCount = inChunk->dataSize / sizeof( IMAAudioFrame );
  259.     
  260.     theExpectedSequenceNumber = inGroupStartSequenceNumber;
  261.     
  262.     for( thePacket = inPackets; thePacket; thePacket = thePacket->next )
  263.     {
  264.         theMissingPacketCount = thePacket->sequenceNum - theExpectedSequenceNumber;
  265.         
  266.         if( theMissingPacketCount )
  267.         {
  268.             for(
  269.                 theIndex = theExpectedSequenceNumber - inGroupStartSequenceNumber;
  270.                 theIndex < theFrameCount; theIndex += inInterleaveCount )
  271.             {
  272.                 memset(
  273.                     &theFrames[ theIndex ], 0,
  274.                     theMissingPacketCount * sizeof( IMAAudioFrame ) );
  275.             }
  276.         }
  277.         
  278.         theExpectedSequenceNumber = thePacket->sequenceNum + 1;
  279.     }
  280.     
  281.     theMissingPacketCount =
  282.         inGroupStartSequenceNumber + inInterleaveCount - theExpectedSequenceNumber;
  283.     
  284.     if( theMissingPacketCount )
  285.     {
  286.         for(
  287.             theIndex = theExpectedSequenceNumber - inGroupStartSequenceNumber;
  288.             theIndex < theFrameCount; theIndex += inInterleaveCount )
  289.         {
  290.             memset(
  291.                 &theFrames[ theIndex ], 0,
  292.                 theMissingPacketCount * sizeof( IMAAudioFrame ) );
  293.         }
  294.     }
  295. }
  296.  
  297.  
  298.  
  299. /* ---------------------------------------------------------------------------
  300.  *        __InterleaveGroupDataSize()
  301.  * ---------------------------------------------------------------------------
  302.  *
  303.  *    Compute the number of octets of data in the interleave group to which the
  304.  *    given packet belongs.
  305.  *
  306.  */
  307.  
  308. static
  309. UInt32
  310. __InterleaveGroupDataSize(
  311.     RTPRssmPacket *        inPacket )
  312. {
  313.     UInt32                        theResult;
  314.     const IMAAudioPayload *        thePayload;
  315.     UInt32                        theInterleaveCount;
  316.     UInt32                        theInterleaveIndex;
  317.     UInt32                        theInterleaveTail;
  318.     
  319.     
  320.     thePayload = __GetPayload( inPacket );
  321.     
  322.     theInterleaveCount = IMAAudioPayloadInterleaveCount( thePayload );
  323.     theInterleaveIndex = IMAAudioPayloadInterleaveIndex( thePayload );
  324.     theInterleaveTail = IMAAudioPayloadInterleaveTail( thePayload );
  325.     
  326.     theResult = theInterleaveCount * inPacket->dataLength;
  327.     
  328.     if( theInterleaveIndex <= theInterleaveTail )
  329.     {
  330.         theResult -=
  331.             sizeof( IMAAudioFrame ) * ( theInterleaveCount - theInterleaveTail - 1 );
  332.     }
  333.     
  334.     else
  335.     {
  336.         theResult += sizeof( IMAAudioFrame ) * ( theInterleaveTail + 1 );
  337.     }
  338.     
  339.     return( theResult );
  340. }
  341.  
  342.  
  343.  
  344. #pragma mark -
  345. #pragma mark *        STANDARD COMPONENT INTERFACE
  346. #pragma mark -
  347. /* ---------------------------------------------------------------------------
  348.  *        S T A N D A R D    C O M P O N E N T    I N T E R F A C E
  349.  * ---------------------------------------------------------------------------
  350.  */
  351.  
  352.  
  353.  
  354. /* ---------------------------------------------------------------------------
  355.  *        + CallComponentOpen() implementation
  356.  * ---------------------------------------------------------------------------
  357.  *
  358.  *    Allocate and initialize storage for instance variables.  When a
  359.  *    reassembler is opened, it is not always called to reassemble data, so this
  360.  *    function doesn't perform any allocations or time-consuming operations that
  361.  *    are needed only to reassemble sample data.  The RTPRssmInitialize()
  362.  *    implementation performs such operations.
  363.  *
  364.  */
  365.  
  366. EXTERN_API( ComponentResult )
  367. RTPRssmIMAAudio_Open(
  368.     RTPRssmIMAAudioInstanceData **    inGlobals,
  369.     ComponentInstance                self )
  370. {
  371.     ComponentResult        theResult = noErr;
  372.     RTPReassembler        theBase;
  373.     
  374.     
  375.     inGlobals =
  376.         REINTERPRET_CAST( RTPRssmIMAAudioInstanceData ** )(
  377.             NewHandleClear( sizeof( **inGlobals ) ) );
  378.     
  379.     if( inGlobals )
  380.     {
  381.         ( **inGlobals ).itself = self;
  382.         ( **inGlobals ).itsFinalDerivation = self;
  383.         
  384.         SetComponentInstanceStorage( self, REINTERPRET_CAST( Handle )( inGlobals ) );
  385.         
  386.         theResult =
  387.             OpenADefaultComponent(
  388.                 kRTPReassemblerType, kRTPBaseReassemblerType, &theBase );
  389.         
  390.         if( theResult == noErr )
  391.         {
  392.             ( **inGlobals ).itsBase = theBase;
  393.             theResult = CallComponentTarget( ( **inGlobals ).itsBase, self );
  394.         }
  395.     }
  396.     
  397.     else
  398.     {
  399.         theResult = MemError();
  400.         
  401.         if( theResult == noErr )
  402.             theResult = memFullErr;
  403.     }
  404.     
  405.     return( theResult );
  406. }
  407.  
  408.  
  409.  
  410. /* ---------------------------------------------------------------------------
  411.  *        + CallComponentClose() implementation
  412.  * ---------------------------------------------------------------------------
  413.  *
  414.  *    Reverse the effects of the CallComponentOpen() implementation.
  415.  *
  416.  */
  417.  
  418. EXTERN_API( ComponentResult )
  419. RTPRssmIMAAudio_Close(
  420.     RTPRssmIMAAudioInstanceData **    inGlobals,
  421.     ComponentInstance                self )
  422. {
  423. #pragma unused( self )
  424.     
  425.     if( inGlobals )
  426.     {
  427.         if( ( **inGlobals ).itsBase )
  428.             CloseComponent( ( **inGlobals ).itsBase );
  429.         
  430.         DisposeHandle( REINTERPRET_CAST( Handle )( inGlobals ) );
  431.     }
  432.     
  433.     return( noErr );
  434. }
  435.  
  436.  
  437.  
  438. /* ---------------------------------------------------------------------------
  439.  *        + CallComponentVersion() implementation
  440.  * ---------------------------------------------------------------------------
  441.  *
  442.  *    Return the instance's version.
  443.  *
  444.  */
  445.  
  446. EXTERN_API( ComponentResult )
  447. RTPRssmIMAAudio_Version(
  448.     RTPRssmIMAAudioInstanceData **    inGlobals )
  449. {
  450. #pragma unused( inGlobals )
  451.     
  452.     return( kComponentVersion );
  453. }
  454.  
  455.  
  456.  
  457. /* ---------------------------------------------------------------------------
  458.  *        + CallComponentTarget() implementation
  459.  * ---------------------------------------------------------------------------
  460.  *
  461.  *    Update the instance's inheritance graph with a new most-derived instance.
  462.  *
  463.  */
  464.  
  465. EXTERN_API( ComponentResult )
  466. RTPRssmIMAAudio_Target(
  467.     RTPRssmIMAAudioInstanceData **    inGlobals,
  468.     ComponentInstance                target )
  469. {
  470.     ComponentResult        theResult;
  471.     
  472.     
  473.     if( ( **inGlobals ).itsBase )
  474.         theResult = CallComponentTarget( ( **inGlobals ).itsBase, target );
  475.     else
  476.         theResult = noErr;
  477.     
  478.     if( theResult == noErr )
  479.         ( **inGlobals ).itsFinalDerivation = target;
  480.     
  481.     return( theResult );
  482. }
  483.  
  484.  
  485.  
  486. #pragma mark -
  487. #pragma mark *        RTP REASSEMBLER INTERFACE
  488. #pragma mark -
  489. /* ---------------------------------------------------------------------------
  490.  *        R T P    R E A S S E M B L E R    I N T E R F A C E
  491.  * ---------------------------------------------------------------------------
  492.  */
  493.  
  494.  
  495.  
  496. /* ---------------------------------------------------------------------------
  497.  *        + RTPRssmInitialize() implementation
  498.  * ---------------------------------------------------------------------------
  499.  *
  500.  *    Prepare to reassemble sample data.  This implementation initializes
  501.  *    instance variables that represent the payload state, opens a new
  502.  *    StreamHandler to process reassembled sample data, and sets options that
  503.  *    determine how its base reassembler handles network packets.
  504.  *
  505.  */
  506.  
  507. EXTERN_API( ComponentResult )
  508. RTPRssmIMAAudio_Initialize(
  509.     RTPRssmIMAAudioInstanceData **    inGlobals,
  510.     RTPRssmInitParams *                inInitParams )
  511. {
  512.     ComponentResult                theResult = noErr;
  513.     IMAAudioPayload                thePayloadAttributes;
  514.     SampleDescriptionHandle        theDescription;
  515.     
  516.     
  517.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPRssmInitializeSelect ) )
  518.         theResult = RTPRssmInitialize( ( **inGlobals ).itsBase, inInitParams );
  519.     
  520.     if( theResult == noErr )
  521.     {
  522.         IMAAudioPayloadInitialize( &thePayloadAttributes );
  523.         
  524.         theResult =
  525.             __GetNewSampleDescription( &thePayloadAttributes, &theDescription );
  526.         
  527.         ( **inGlobals ).itsPayloadAttributes = thePayloadAttributes;
  528.         
  529.         if( theResult == noErr )
  530.         {
  531.             theResult =
  532.                 RTPRssmNewStreamHandler(
  533.                     ( **inGlobals ).itsFinalDerivation, SoundMediaType,
  534.                     theDescription, kIMAAudioPayloadRTPTimeScale, NULL );
  535.             
  536.             DisposeHandle( REINTERPRET_CAST( Handle )( theDescription ) );
  537.             
  538.             if( theResult == noErr )
  539.             {
  540.                 theResult =
  541.                     RTPRssmSetCapabilities(
  542.                         ( **inGlobals ).itsFinalDerivation,
  543.                         kRTPRssmTrackLostPacketsFlag | kRTPRssmQueueAndUseMarkerBitFlag,
  544.                         -1L );
  545.             }
  546.         }
  547.     }
  548.     
  549.     return( theResult );
  550. }
  551.  
  552.  
  553.  
  554. /* ---------------------------------------------------------------------------
  555.  *        + RTPRssmComputeChunkSize() implementation
  556.  * ---------------------------------------------------------------------------
  557.  *
  558.  *    Use the packet list to determine the size of the data buffer needed to
  559.  *    pass data from these network packets to the StreamHandler.
  560.  *    
  561.  *    For this reassembler, the chunk size is the audio data size for the entire
  562.  *    interleave group to which the given packets belong.  (The data is
  563.  *    packetized such that the base reassembler can automatically group
  564.  *    incoming packets by interleave group, so the packets in the list will be
  565.  *    all those packets, and only those packets, from a single interleave
  566.  *    group.)  The size cannot be computed by summing the data sizes of network
  567.  *    packets received, since some packets might be lost.  Instead, the size is
  568.  *    determnined, through a call to __InterleaveGroupDataSize() defined above,
  569.  *    by inspecting the payload header and data size of the first packet.
  570.  *    
  571.  *    This function also updates the StreamHandler's SampleDescription when the
  572.  *    sample rate or channel count changes.
  573.  *
  574.  */
  575.  
  576. EXTERN_API( ComponentResult )
  577. RTPRssmIMAAudio_ComputeChunkSize(
  578.     RTPRssmIMAAudioInstanceData **    inGlobals,
  579.     RTPRssmPacket *                    inPacketListHead,
  580.     SInt32                             inFlags,
  581.     UInt32 *                        outChunkDataSize )
  582. {
  583. #pragma unused( inFlags )
  584.  
  585.     ComponentResult                theResult = noErr;
  586.     const IMAAudioPayload *        thePayload;
  587.     UInt32                        theChannelCount;
  588.     UnsignedFixed                theSampleRate;
  589.     SampleDescriptionHandle        theDescription;
  590.     
  591.     
  592.     thePayload = __GetPayload( inPacketListHead );
  593.     
  594.     theChannelCount = IMAAudioPayloadChannelCount( &( **inGlobals ).itsPayloadAttributes );
  595.     theSampleRate = IMAAudioPayloadSampleRate( &( **inGlobals ).itsPayloadAttributes );
  596.     
  597.     if(
  598.         IMAAudioPayloadChannelCount( thePayload ) != theChannelCount  ||
  599.         IMAAudioPayloadSampleRate( thePayload ) != theSampleRate )
  600.     {
  601.         theResult = __GetNewSampleDescription( thePayload, &theDescription );
  602.         
  603.         if( theResult == noErr )
  604.         {
  605.             theResult =
  606.                 RTPRssmSetSampleDescription(
  607.                     ( **inGlobals ).itsFinalDerivation, theDescription );
  608.             
  609.             if( theResult == noErr )
  610.                 ( **inGlobals ).itsPayloadAttributes = *thePayload;
  611.             
  612.             DisposeHandle( REINTERPRET_CAST( Handle )( theDescription ) );
  613.         }
  614.     }
  615.     
  616.     *outChunkDataSize = __InterleaveGroupDataSize( inPacketListHead );
  617.     
  618.     return( theResult );
  619. }
  620.  
  621.  
  622.  
  623. /* ---------------------------------------------------------------------------
  624.  *        + RTPRssmAdjustPacketParams() implementation
  625.  * ---------------------------------------------------------------------------
  626.  *
  627.  *    Adjust fields of the RTPRssmPacket to reflect the properties of its
  628.  *    payload.  The payload format used by this reassembler defines a
  629.  *    fixed-length header that immediately precedes the audio data.  Overriding
  630.  *    RTPRssmAdjustPacketParams() gives the reassembler a chance to update the
  631.  *    RTPRssmPacket data structure for each packet to reflect its payload header
  632.  *    length and audio data length.
  633.  *
  634.  */
  635.  
  636. EXTERN_API( ComponentResult )
  637. RTPRssmIMAAudio_AdjustPacketParams(
  638.     RTPRssmIMAAudioInstanceData **    inGlobals,
  639.     RTPRssmPacket *                    inPacket,
  640.     SInt32                            inFlags )
  641. {
  642. #pragma unused( inGlobals, inFlags )
  643.     
  644.     UInt32                theHeaderSize;
  645.     IMAAudioPayload *    thePayload;
  646.     
  647.     
  648.     theHeaderSize = sizeof( thePayload->itsFixedHeader );
  649.     
  650.     inPacket->payloadHeaderLength = theHeaderSize;
  651.     inPacket->dataLength -= theHeaderSize;
  652.     
  653.     return( noErr );
  654. }
  655.  
  656.  
  657.  
  658. /* ---------------------------------------------------------------------------
  659.  *        + RTPRssmCopyDataToChunk() implementation
  660.  * ---------------------------------------------------------------------------
  661.  *
  662.  *    Copy sample data from a packet list to the data buffer described by an
  663.  *    SHChunkRecord.  The payloads processed by this reassembler indicate where
  664.  *    interleave audio data from each payload.  This function iterates through
  665.  *    the packets, copying the data to the correct position in the chunk.  The
  666.  *    function then calls __FillMissingData(), defined above, to synthesize lost
  667.  *    packet data.
  668.  *
  669.  */
  670.  
  671. EXTERN_API( ComponentResult )
  672. RTPRssmIMAAudio_CopyDataToChunk(
  673.     RTPRssmIMAAudioInstanceData **    inGlobals,
  674.     RTPRssmPacket *                    inPacketListHead,
  675.     UInt32                            inMaxChunkDataSize,
  676.     SHChunkRecord *                    inChunk,
  677.     SInt32                            inFlags )
  678. {
  679. #pragma unused( inGlobals, inFlags )
  680.     
  681.     ComponentResult                theResult = noErr;
  682.     UInt32                        theFrameCount;
  683.     IMAAudioFrame *                theFrames;
  684.     RTPRssmPacket *                thePacket;
  685.     const IMAAudioPayload *        thePayload;
  686.     UInt16                        theGroupStartSequenceNumber;
  687.     UInt32                        theInterleaveCount;
  688.     UInt32                        theInterleaveIndex;
  689.     UInt32                        thePacketFrameCount;
  690.     UInt32                        theSourceIndex;
  691.     UInt32                        theTargetIndex;
  692.     
  693.     
  694.     /*    IMPORTANT    The sequence number computations in this function work
  695.                     because the packets are in order and the separation
  696.                     between the packets is guaranteed to be within the
  697.                     precision of the RTP sequence number field (i.e., less
  698.                     than 16 bits, or 65536 packets).  When computing with
  699.                     sequence numbers of packets that might be separated by
  700.                     more than 65535 packets, a reassembler must extend
  701.                     the precision of the sequence numbers, for instance by
  702.                     using the inNumWraparounds parameter of
  703.                     RTPRssmHandleNewPacket() or by using the timeStamp
  704.                     field of RTPRssmPacket structures.
  705.     */
  706.     
  707.     inChunk->dataSize = __InterleaveGroupDataSize( inPacketListHead );
  708.     
  709.     if( inChunk->dataSize > inMaxChunkDataSize )
  710.     {
  711.         /* this should never happen */
  712.         
  713.         theResult = buffersTooSmall;
  714.     }
  715.     
  716.     else
  717.     {
  718.         theFrameCount = inChunk->dataSize / sizeof( IMAAudioFrame );
  719.         theFrames =
  720.             REINTERPRET_CAST( IMAAudioFrame * )(
  721.                 CONST_CAST( UInt8 * )( inChunk->dataPtr ) );
  722.         
  723.         thePayload = __GetPayload( inPacketListHead );
  724.         
  725.         theInterleaveCount = IMAAudioPayloadInterleaveCount( thePayload );
  726.         
  727.         theGroupStartSequenceNumber =
  728.             inPacketListHead->sequenceNum - IMAAudioPayloadInterleaveIndex( thePayload );
  729.         
  730.         for( thePacket = inPacketListHead; thePacket; thePacket = thePacket->next )
  731.         {
  732.             thePayload = __GetPayload( thePacket );
  733.             
  734.             theInterleaveIndex = thePacket->sequenceNum - theGroupStartSequenceNumber;
  735.             thePacketFrameCount = thePacket->dataLength / sizeof( IMAAudioFrame );
  736.             
  737.             for( theSourceIndex = 0; theSourceIndex < thePacketFrameCount; theSourceIndex++ )
  738.             {
  739.                 theTargetIndex =
  740.                     ( theSourceIndex * theInterleaveCount ) + theInterleaveIndex;
  741.                 
  742.                 if( theTargetIndex < theFrameCount )
  743.                 {
  744.                     theFrames[ theTargetIndex ] =
  745.                         thePayload->itsAudioFrames[ theSourceIndex ];
  746.                 }
  747.             }
  748.         }
  749.         
  750.         __FillMissingData(
  751.             inPacketListHead, theGroupStartSequenceNumber, theInterleaveCount, inChunk );
  752.     }
  753.     
  754.     return( theResult );
  755. }
  756.  
  757.  
  758.  
  759. /* ---------------------------------------------------------------------------
  760.  *        + RTPRssmSendPacketList() implementation
  761.  * ---------------------------------------------------------------------------
  762.  *
  763.  *    Prepare to process or discard a list of packets.  If the base detects that
  764.  *    some network packets were lost, overriding RTPRssmSendPacketList() gives
  765.  *    the reassembler a chance to decide whether it can handle the remaining
  766.  *    packets.  This reassembler tolerates any amount of packet loss, so this
  767.  *    function simply clears the kRTPRssmLostSomePackets flag before delegating
  768.  *    to the base.  When a reassembler is able to recover from packet loss,
  769.  *    turning off the kRTPRssmLostSomePackets flag before delegating the call to
  770.  *    the base reassembler prevents the base from discarding the packets.
  771.  *
  772.  */
  773.  
  774. EXTERN_API( ComponentResult )
  775. RTPRssmIMAAudio_SendPacketList(
  776.     RTPRssmIMAAudioInstanceData **    inGlobals,
  777.     RTPRssmPacket *                    inPacketListHead,
  778.     const TimeValue64 *                inLastChunkPresentationTime,
  779.     SInt32                            inFlags )
  780. {
  781.     return(
  782.         RTPRssmSendPacketList(
  783.             ( **inGlobals ).itsBase, inPacketListHead, inLastChunkPresentationTime,
  784.             inFlags &= ~kRTPRssmLostSomePackets ) );
  785. }
  786.  
  787.  
  788.  
  789. /* ---------------------------------------------------------------------------
  790.  *        + RTPRssmHasCharacteristic() implementation
  791.  * ---------------------------------------------------------------------------
  792.  *
  793.  *    Indicate whether the reassembler has the specified characteristic.  This
  794.  *    reassembler requires ordered packet lists.  All other characteristics are
  795.  *    delegated to the base.
  796.  *
  797.  */
  798.  
  799. EXTERN_API( ComponentResult )
  800. RTPRssmIMAAudio_HasCharacteristic(
  801.     RTPRssmIMAAudioInstanceData **    inGlobals,
  802.     OSType                             inCharacteristic,
  803.     Boolean *                        outHasIt )
  804. {
  805.     ComponentResult        theResult;
  806.     
  807.     
  808.     if( inCharacteristic == kRTPRssmRequiresOrderedPacketsCharacteristic )
  809.     {
  810.         *outHasIt = true;
  811.         theResult = noErr;
  812.     }
  813.  
  814.     else
  815.     {
  816.         theResult =
  817.             RTPRssmHasCharacteristic( ( **inGlobals ).itsBase, inCharacteristic, outHasIt );
  818.     }
  819.     
  820.     return( theResult );
  821. }
  822.  
  823.  
  824.  
  825. /* ---------------------------------------------------------------------------
  826.  *        + RTPRssmReset() implementation
  827.  * ---------------------------------------------------------------------------
  828.  *
  829.  *    End processing of the current stream of network packets and prepare to
  830.  *    process a new, possibly unrelated, stream.  This implementation simply
  831.  *    resets its base.
  832.  *
  833.  */
  834.  
  835. EXTERN_API( ComponentResult )
  836. RTPRssmIMAAudio_Reset(
  837.     RTPRssmIMAAudioInstanceData **    inGlobals,
  838.     SInt32                            inFlags )
  839. {
  840.     ComponentResult        theResult;
  841.     
  842.     
  843.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPRssmResetSelect ) )
  844.         theResult = RTPRssmReset( ( **inGlobals ).itsBase, inFlags );
  845.     else
  846.         theResult = noErr;
  847.     
  848.     return( theResult );
  849. }
  850.